<html xmlns="http://www.w3.org/1999/xhtml" id="lzunit">
<head>
    <title>Unit Testing</title>
</head>

<body>
 
<h1>Unit Testing</h1>

<p><classname link="true">LzUnit</classname> is an implementation of the xUnit testing framework, for
OpenLaszlo applications. LzUnit is useful in automated unit-testing of Laszlo
applications and libraries.</p>

<h2><a name="overview">Overview</a></h2>

<p>The functionality provided by the LzUnit framework is essentially comprised of two public classes &#x2014; 
  <classname>TestCase</classname> and <classname>TestSuite</classname>. Each <classname>TestSuite</classname>
  contains one or more children that are instances of <classname>TestCase</classname>. An LZX program that 
  consists of a <tagname>TestSuite</tagname> will, when loaded, automatically run all of its child <classname>TestCase</classname>s and report the number of test cases run, the number of failures, and the number of runtime errors. If any 
  failures occur, an obvious error message is presented.</p>

<h2><a name="TestCases">Writing test cases</a></h2>

<p>An LzUnit test case is generally defined as an instance of <classname>TestCase</classname> or its subclass. 
LzUnit test cases contain one or more logical tests that are represented by corresponding methods on the 
<tagname>TestCase</tagname>. In order for a test to be recognized by and added to the enclosing 
<tagname>TestSuite</tagname>, its name must start with "<code>test</code>". Within each test, you use the standard 
<code>assert<i>XXX</i>()</code> methods of the xUnit API to define the checkpoints that will form the basis of your test.
Below is an example of typical usage of the LzUnit framework that shows a success, a failure, and a runtime error.</p>


<example title="LzUnit example">
&lt;canvas debug="true" height="500"&gt;
  &lt;include href="lzunit"/&gt;
  &lt;debug y="10"/&gt;

  &lt;TestSuite&gt;
    &lt;TestCase&gt;
      &lt;attribute name="prop1" value="'foo'" when="once"/&gt;
      &lt;text name="mytext" width="200" bgcolor="blue" text="LzUnit example"/&gt;

      &lt;method name="testsuccess"&gt;
        assertEquals(prop1, 'foo')
      &lt;/method&gt;
      &lt;method name="testfailure"&gt;
        assertTrue(mytext.multiline, "This is not a multiline text field")
      &lt;/method&gt;
      &lt;method name="testerror"&gt;
        callFoo()
      &lt;/method&gt;
    &lt;/TestCase&gt;
  &lt;/TestSuite&gt;
&lt;/canvas&gt;
</example>

<p>In this example, as is the case with any tests that include visual elements, you do not see the text field because it was 
positioned below the test status panel by the layout which controls them.</p>

<note>You must explicitly tell the compiler to include the LzUnit library in your code by using the 
<tagname>include</tagname> tag.</note>
<p>Also, when writing a test suite, remember to enable the debugger, as is done in the example above, in order for runtime 
errors to be detected. If you would like to see debugger warnings, but do not want them to affect results of the test run, 
you should set a global flag <varname>catchErrors</varname> to <code>false</code> in a <tagname>script</tagname> tag.</p>

<h2><a name="advanced">Advanced techniques</a></h2>
<h3><a name="syncexec">Sequential execution of tests</a></h3>
<p>By default, the order of execution of individual tests within a test case is not guaranteed. That is, every test
is executed at the next idle event (see the <classname>LzIdle</classname> documentation for details), and thus
tests that take longer to execute may finish after those tests that were started later but do not need as much time to complete.
If it is important that tests are run in the order they are written, set the global flag <varname>asynchronousTests</varname> to <code>false</code>,
as in the following example.</p>

<example title="Sequential execution of tests">
&lt;canvas debug="true" height="400"&gt;
  &lt;include href="lzunit"/&gt;

  &lt;debug y="10"/&gt;

  &lt;script&gt;
    asynchronousTests = false
  &lt;/script&gt;

  &lt;class name="syncrun" extends="TestCase"&gt;
    &lt;attribute name="counter" value="1" when="once"/&gt;
    &lt;method name="testfirst"&gt;
      assertEquals(1, counter++)
    &lt;/method&gt;

    &lt;method name="testsecond"&gt;
      assertEquals(2, counter++)
    &lt;/method&gt;

    &lt;method name="testthird"&gt;
      assertEquals(3, counter++)
    &lt;/method&gt;
  &lt;/class&gt;

  &lt;TestSuite&gt;
    &lt;syncrun/&gt;
  &lt;/TestSuite&gt;
&lt;/canvas&gt;
</example>

<h3><a name="defertest">Deferred test execution</a></h3>
<p>In many cases, you will encounter that the objects that your test case incorporates are not ready for 
inspection by the time it runs. Some of the common examples of this scenario are tests that include animation, 
loading of remote data or media, and instantiation of classes declared with deferred initialization stages. The 
approach illustrated by the example below involves waiting for the event that signals completion of a specific 
action, and putting the checkpoint in the event handler method.</p>

<example title="Deferred execution of tests">
&lt;canvas debug="true" height="400"&gt;
    &lt;include href="lzunit"/&gt;
    
    &lt;debug y="10"/&gt;
    &lt;TestSuite&gt;
        &lt;TestCase&gt;
            &lt;view name="redbox" bgcolor="red" width="50" height="50"&gt;
                &lt;animator name="anm" attribute="x" from="0" to="200" duration="1000" start="false" 
                relative="false" onstop="parent.parent.checkStatus()"/&gt;
            &lt;/view&gt;
            &lt;method name="testanim"&gt;
                redbox.anm.doStart()
            &lt;/method&gt;
            &lt;method name="checkStatus"&gt;
                assertEquals(200, redbox.x)
            &lt;/method&gt;
        &lt;/TestCase&gt;
    &lt;/TestSuite&gt;
&lt;/canvas&gt;
</example>

<!--p>Notice that although you can call any of the methods of the <classname>Test</classname> API
anywhere within the body of your <tagname>TestCase</tagname>, we still define a "testXXX" method on our test case. 
This is done so that the display of the test progress correctly reflects the total number of tests run 
(the progress indicator takes into account the number of test methods on each <tagname>TestCase</tagname>).</p-->

<h3><a name="preposttest">Test setup and cleanup</a></h3>
<p>Sometimes it is necessary to reset execution environment to its initial state before running every test in a single
test case. The way to do so is to override the <method classname="TestCase">setUp</method> and, optionally,
<method classname="TestCase">tearDown</method> methods of <classname>TestCase</classname> (the default
implementation of these methods is a no-op). These methods are called before and after each of the test methods are 
invoked. Here's an example of their use.</p>

<example title="setUp and tearDown">
&lt;canvas debug="true" height="400"&gt;
  &lt;include href="lzunit"/&gt;

  &lt;debug y="10"/&gt;

  &lt;dataset name="places"&gt;
    &lt;country name="U.S."&gt;
      &lt;state code="CA" capitol="Sacramento"&gt;
        &lt;city&gt;San Francisco&lt;/city&gt;
        &lt;city&gt;Los Angeles&lt;/city&gt;
        &lt;city&gt;San Diego&lt;/city&gt;
      &lt;/state&gt;
      &lt;state code="NJ" capitol="Trenton"&gt;
        &lt;city&gt;Newark&lt;/city&gt;
      &lt;/state&gt;
      &lt;state code="NY" capitol="Albany"&gt;
        &lt;city&gt;Buffalo&lt;/city&gt;
        &lt;city&gt;New York City&lt;/city&gt;
      &lt;/state&gt;
    &lt;/country&gt;
  &lt;/dataset&gt;
    
  &lt;TestSuite&gt;
    &lt;TestCase&gt;
      &lt;attribute name="start" value="'places:/country[1]'"/&gt;
      &lt;datapointer name="nav" xpath="$once{parent.start}"/&gt;
      &lt;<em>method name="setUp"</em>&gt;
        // Move pointer to first state in selected country
        nav.selectChild()
      &lt;/method&gt;

      &lt;<em>method name="tearDown"</em>&gt;
        // Reset pointer to starting position
        nav.setXPath(start)
      &lt;/method&gt;

      &lt;method name="testsettext"&gt;
        assertTrue(nav.selectChild())
        assertTrue(nav.selectNext())

        var oldText = nav.getNodeText()
        nav.setNodeText('Oakland')
        assertEquals('Oakland', nav.xpathQuery('text()'))
        nav.setNodeText(oldText)
        assertEquals(oldText, nav.getNodeText())
      &lt;/method&gt;

      &lt;method name="testBumpChild"&gt;
        assertTrue(nav.selectNext(2))
        assertEquals(2, nav.getNodeCount())
        assertTrue(nav.selectChild())
        nav.deleteNode()
        assertFalse('Buffalo', nav.getNodeText())
        assertTrue(nav.selectParent())
        assertEquals(1, nav.getNodeCount())
      &lt;/method&gt;
    &lt;/TestCase&gt;
  &lt;/TestSuite&gt;
&lt;/canvas&gt;
</example>

    <fixme>
Correct. It is meant for running non-interactive test suites and it cannot emulate the end user - for that an external tool like WinRunner would have to be used (with limited success).

Antun Karlovac wrote:

Our unit testing class is not for testing the UI of Laszlo apps, right?
You can't use it to hit buttons, etc?
-Antun
</fixme>

<h2>Chaining tests</h2>
<p>
Consider the case of a testSuite that has two tests for animation.  The test will report that it hasn't failed *before* the test is complete. This is to be expected, since the animator's <method>doStart</method> returns right away, and the test progress bar fills up as soon as the test method returns. But that does not invalidate the test results, since failures will still be clearly reported. To see that this is so, try inserting <tt>assertTrue(false)</tt> after the first assertion and see what happens.
</p>
<p>If you are testing animation you need to start your second test from the callback of the first.  Results are often different when you run animations sequentially or simultaneously.
</p>
<p>
If you declare a sequential animatorgroup around the animators, you can chain the checkpoints, without having to start the individual animators, as shown below.</p>
<example title="Chaining tests">
&lt;canvas height ="300" width="400" debug="true"&gt;
  &lt;debug y="40"/&gt;
  &lt;view&gt;
    &lt;view id="bluebox" bgcolor="blue" width="30" height="30"&gt;
      &lt;animatorgroup name="AG1" attribute="x" process="sequential" start="false" relative="false"&gt;
        &lt;animator from="0" to="100" duration="2000"
            onstop="canvas.animatorsuite.animatorcase.checkSimpleXAnim()"/&gt;
        &lt;animator from="0" to="200" duration="3000"
            onstop="canvas.animatorsuite.animatorcase.checkSimpleXAnim2()"/&gt;
      &lt;/animatorgroup&gt;
    &lt;/view&gt;
  &lt;/view&gt;
  
  &lt;TestSuite name="animatorsuite"&gt;
   &lt;TestCase name="animatorcase"&gt;
     &lt;method name="testSimpleXAnim"&gt;
       bluebox.AG1.doStart()
     &lt;/method&gt;
     &lt;method name="checkSimpleXAnim"&gt;
       assertEquals(100, bluebox.x);
     &lt;/method&gt;
     &lt;method name="checkSimpleXAnim2"&gt;
       assertEquals(200, bluebox.x);
       Debug.write('--- test complete ---');
     &lt;/method&gt;
   &lt;/TestCase&gt;
  &lt;/TestSuite&gt;
&lt;/canvas&gt;
</example>
<p>
Of course, running both animators simultaneously will superimpose the effect of each on the other and the tests will fail; this is true of any simultaneous animators applied to the same attribute of the same object.
</p>

<!-- See other chapters in the D3 guide and also the wiki for more informtion on formatting chapters --> 
<!-- Here is a list of some topics you may want to discuss in this chapter-->

</body>
</html>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2001-2004 Laszlo Systems, Inc.  All Rights Reserved.              *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
